package com.hhss.qishi.config.log.webLog;

import com.hhss.qishi.config.log.Log;
import com.hhss.qishi.service.system.WebLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * WebLog切面类
 * 用于识别、记录用户的操作并存入数据库
 * @Author :Administrator
 * @Description
 * @Date :2019-05-28 15:55.
 */
@Aspect	// 这是一个切面
@Component
public class WebLogAspect {

	//ThreadLocal保证不受其他线程影响，用于记录接口响应时间
	private static ThreadLocal<com.hhss.qishi.entity.system.WebLog> threadLocal = new ThreadLocal<>();

	@Log
	Logger logger;

	@Autowired
	private WebLogService webLogService;

	//切点， 每一个controller请求方法
	@Pointcut("@annotation(com.hhss.qishi.config.log.webLog.WebLog)")
	public void pointCut(){}

	/**
	 * 前置增强
	 * @param joinPoint
	 */
	@Before(value = "pointCut()")
	public void doBefore(JoinPoint joinPoint) {

		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		//请求的内容，记录url、method、ip
		logger.info("URL==>" + request.getRequestURL().toString() + "," +
				"METHOD==>" + request.getMethod() + "," +
				"IP==>" + request.getRemoteAddr());
		//请求参数，将value数组转成字符串
		Map<String, String[]> params = request.getParameterMap();
		Map<String,String> args = new HashMap<>();
		for (Map.Entry<String,String[]> temp : params.entrySet()) {
			args.put(temp.getKey(), Arrays.toString(temp.getValue()));
		}
		//连接点的签名可以跟踪到程序具体类、具体方法，记录一下方法和参数
		logger.info("CLASS_METHOD==>" + joinPoint.getSignature().getDeclaringTypeName() + "." +joinPoint.getSignature().getName() + "," +
				"ARGS==>" + args);

		MethodSignature ms = (MethodSignature)joinPoint.getSignature();
		WebLog wl = ms.getMethod().getAnnotation(WebLog.class);
		// 组织应用日志实体并存入threadLocal
		com.hhss.qishi.entity.system.WebLog webLog = new com.hhss.qishi.entity.system.WebLog();
		webLog.setUserName("");
		webLog.setModuleName(wl.module());
		webLog.setOperate(wl.operate());
		webLog.setNormal("1");
		webLog.setTimeCost(System.currentTimeMillis());
		webLog.setIp(request.getRemoteAddr());
		webLog.setUrl(request.getRequestURL().toString());
		webLog.setParameter(args.toString());
		//记录请求接口开始时间
		threadLocal.set(webLog);
	}

	/**
	 * 后置增强
	 * @param joinPoint
	 */
	@AfterReturning(pointcut = "pointCut()")
	public void doAfter(JoinPoint joinPoint){

	}

	/**
	 * 异常增强
	 * @param joinPoint
	 * @param exception
	 */
	@AfterThrowing(pointcut="pointCut()",throwing = "exception")
	public void doAfterThrow(JoinPoint joinPoint,Throwable exception) {
		com.hhss.qishi.entity.system.WebLog webLog = threadLocal.get();
		webLog.setNormal("0");
		webLog.setDescription(exception.getMessage());
		threadLocal.set(webLog);
	}

	/**
	 * 最后增强
	 * @param joinPoint
	 * @param returnMsg
	 */
	@AfterReturning(pointcut = "pointCut()",returning = "returnMsg")
	public void doAfterReturn(JoinPoint joinPoint,Object returnMsg) {
		//记录一下接口响应时间
		com.hhss.qishi.entity.system.WebLog webLog = threadLocal.get();
		Long reponseTime = System.currentTimeMillis() - webLog.getTimeCost();
		webLog.setTimeCost(reponseTime);
		webLogService.add(webLog);
		//删除threadLocal变量副本
		threadLocal.remove();
	}

	// test 用户记录aspect注解间的执行顺序呢
	public Object test(Object proxy, Method method, Object[] args) throws Throwable {
		Object result;
		try {
			//@Before
			result = method.invoke(proxy, args);
			//@After
			return result;
		} catch (InvocationTargetException e) {
			Throwable targetException = e.getTargetException();
			//@AfterThrowing
			throw targetException;
		} finally {
			//@AfterReturning
		}
	}
}
